package com.passion.common.threadpool;

import cn.hippo4j.core.executor.DynamicThreadPool;
import cn.hippo4j.core.executor.support.ThreadPoolBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 类描述：线程池配置类
 *
 * @author ZhuYin
 * @since 2024年12月26日
 */
@Slf4j
@ConditionalOnProperty(prefix = "spring.dynamic.thread-pool", name = "enable", havingValue = "true")
@Configuration
public class ThreadPoolConfig implements CommandLineRunner {

    @Value("${spring.dynamic.thread-pool.executors[0].thread-pool-id}")
    private String cpuIntensiveThreadPool;

    @Value("${spring.dynamic.thread-pool.executors[1].thread-pool-id}")
    private String ioIntensiveThreadPool;

    @Value("${spring.dynamic.thread-pool.executors[2].thread-pool-id}")
    private String scheduledThreadPool;

    @Value("${spring.dynamic.thread-pool.executors[3].thread-pool-id}")
    private String asyncTaskThreadPool;

    @Value("${spring.dynamic.thread-pool.executors[4].thread-pool-id}")
    private String asyncLogTaskThreadPool;

    /**
     * 方法说明：初始化cpu密集型任务线程池
     * 如图像处理、加密解密
     *
     * @return 返回线程池对象
     * @author ZhuYin
     * @since 2024年12月27日
     */
    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor cpuIntensiveThreadPool() {
        return ThreadPoolBuilder.builder()
                .threadFactory(cpuIntensiveThreadPool)
                .threadPoolId(cpuIntensiveThreadPool)
                .dynamicPool()
                .build();
    }

    /**
     * 方法说明：初始化io密集型任务线程池
     * 常见I/O操作，如网络请求、文件读写，数据库访问等
     *
     * @return 返回线程池对象
     * @author ZhuYin
     * @since 2024年12月27日
     */
    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor ioIntensiveThreadPool() {
        return ThreadPoolBuilder.builder()
                .threadFactory(ioIntensiveThreadPool)
                .threadPoolId(ioIntensiveThreadPool)
                .dynamicPool()
                .build();
    }

    /**
     * 方法说明：初始化用来执行定时任务的线程池
     *
     * @return 返回线程池对象
     * @author ZhuYin
     * @since 2024年12月27日
     */
    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor scheduledThreadPool() {
        return ThreadPoolBuilder.builder()
                .threadFactory(scheduledThreadPool)
                .threadPoolId(scheduledThreadPool)
                .dynamicPool()
                .build();
    }

    /**
     * 方法说明：初始化用来执行异步任务的线程池
     *
     * @return 返回线程池对象
     * @author ZhuYin
     * @since 2024年12月27日
     */
    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor asyncTaskThreadPool() {
        return ThreadPoolBuilder.builder()
                .threadFactory(asyncTaskThreadPool)
                .threadPoolId(asyncTaskThreadPool)
                .dynamicPool()
                .build();
    }

    /**
     * 方法说明：初始化用来执行异步日志任务的线程池
     *
     * @return 返回线程池对象
     * @author ZhuYin
     * @since 2024年12月27日
     */
    @Bean
    @DynamicThreadPool
    public ThreadPoolExecutor asyncLogTaskThreadPool() {
        return ThreadPoolBuilder.builder()
                .threadFactory(asyncLogTaskThreadPool)
                .threadPoolId(asyncLogTaskThreadPool)
                .dynamicPool()
                .build();
    }

    @Override
    public void run(String... args) {
        log.info("System cores：{}", Runtime.getRuntime().availableProcessors());
        this.printThreadPoolInfo(cpuIntensiveThreadPool, ThreadPoolHelper.cpuIntensiveThreadPool);
        this.printThreadPoolInfo(ioIntensiveThreadPool, ThreadPoolHelper.ioIntensiveThreadPool);
        this.printThreadPoolInfo(scheduledThreadPool, ThreadPoolHelper.scheduledThreadPool);
        this.printThreadPoolInfo(asyncTaskThreadPool, ThreadPoolHelper.asyncTaskThreadPool);
        this.printThreadPoolInfo(asyncLogTaskThreadPool, ThreadPoolHelper.asyncLogTaskThreadPool);
    }

    private void printThreadPoolInfo(String threadPoolId, ThreadPoolExecutor executor) {
        String sb =
                "\n||===============================================================================================" +
                "\n||  Dynamic Thread Pool Name: {}" +
                "\n||            Core Pool Size: " + executor.getCorePoolSize() +
                "\n||         Maximum Pool Size: " + executor.getMaximumPoolSize() +
                "\n||            Queue Capacity: " + executor.getQueue().size() + "/" + executor.getQueue().remainingCapacity() +
                "\n||           Keep Alive Time: " + executor.getKeepAliveTime(TimeUnit.SECONDS) + " seconds" +
                "\n||           Rejected Policy: " + executor.getRejectedExecutionHandler().getClass().getSimpleName() +
                "\n||Allows Core Thread Timeout: " + executor.allowsCoreThreadTimeOut() +
                "\n||" +
                "\n||                     Usage: You can simply use it like:" +
                "\n||                                ThreadPoolHelper.{}.execute(() -> { ... })" +
                "\n||                            or  CompletableFuture.runAsync(() -> { ... }, ThreadPoolHelper.{})" +
                "\n||================================================================================================\n";
        log.info(sb, threadPoolId, threadPoolId, threadPoolId);
    }
}